/**
 * 迭代器模式（iterator-pattern）：
 *    一个相对简单的模式。目前绝大多数语言都内置了迭代器，以至于大家都不觉得这是一种设计模式。
 * 
 *   概念：
 *      迭代器模式是指提供一种方法访问一个聚合对象中的各个元素，而又不需要暴露该对象的内部表示。
 * 
 *     个人理解：
 *       遍历聚合对象中的各个（某些）元素，并执行一个回调方法。
 * 
 *    下面实现一个简单的迭代器方法
 */

var each = function(arr, callback) {
    for (let i = 0; i < arr.length; i++) {
        callback.call(arr[i], i, arr[i])
    }
}

/** 
each([1,2,3,4,5], function(i, el) {
    console.log("index:", i, "item:", el)
})
*/

/**
 * 迭代器还有一种类似： 外部迭代器
 * 
 * 内部迭代器： 
 *    在迭代器内部已经定义好了迭代规则。如：迭代的方向， 迭代终止条件
 *    内部迭代器在调用的时候非常方便，外界不用关心内部实现。
 *    每一次调用时，迭代器的规则就已经指定，如果遇到不一样的迭代规则，此时内部迭代器并不优雅。
 */




/**
 * 外部迭代器：
 *   迭代器必须显式请求迭代下一个元素（iterator.next()）
 * 
 *   外部迭代器虽然增加了调用的复杂度，但增加了迭代器的灵活性，
 *   我们可以手工控制迭代过程或者顺序。
 *  
 *   Generators函数应该就是一种外部迭代器的实现。
 */
var Iterator = function (obj) {
    var current = 0
    var next = function() {
        current += 1 
    }

    var isDone = function () {
        return current >= obj.length
    }

    var getCurrent = function () { 
        return obj[current]
    }

    return {
        next: next,
        length: obj.length,
        isDone: isDone,
        current: getCurrent
    }
} 

/**
 * 通过这个迭代器可以优雅的实现两个数组比较
 */
var compare = function (iterator1, iterator2) { 

    if (iterator1.length !== iterator2.length) return false

    while (!iterator1.isDone() && !iterator2.isDone()) {
        if (iterator1.current() !== iterator2.current()) {
            return false
        }
        iterator1.next()
        iterator2.next()
    }
    return true
}

const iterator1 = Iterator([1, 2, 3])
const iterator2 = Iterator([1, 2, 3])

// console.log(compare(iterator1, iterator2)? "数组相等" : "数组不相等")

/**
 * 迭代器并不只是迭代数组
 * 
 *   迭代器不仅能迭代数组， 还可以迭代一些类数组对象。比如arguments, {a:1, n:2, c:3}等。
 *   其必须具备的就是对象拥有一个length属性可以访问，并且可以通过下标来访问对象中的各个元素。
 * 
 *   其中for ... of 可以用来循环数组，对象字面量则可以通过 for ... in 来访问其中的各个属性
 *   的值来达到目的。
 * 
 *  迭代器可以中止
 *    在for循环中，可以通过break来跳出循环。所以在迭代器模式中，可以利用这个提前终止迭代。
 */

var each = function(arr, callback) {
    var result;
    for (let i = 0; i < arr.length; i++) {
        result = callback.call(arr[i], i, arr[i])
        if(result === false) break 
    }
}

each([1, 2, 3, 4, 5, 6, 7], function (i, el) { 
    if (el > 3) { 
        return false
    }

    console.log("el:", el)
})